package cnki.kg.demo.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
@Lazy(false)
@Slf4j
@Configuration
public class RedisUtil {

    private static RedisTemplate<String, Object> redisTemplate;

    @Autowired
    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        RedisUtil.redisTemplate = redisTemplate;
    }

    /**
     * 指定缓存失效时间
     *
     * @param key  键
     * @param time 时间(秒)
     * @return
     */
    public static boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }

    /**
     * 根据key 获取过期时间
     *
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public static long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判断key是否存在
     *
     * @param key 键
     * @return true 存在 false不存在
     */
    public static boolean hasKey(String key) {
        try {
            if(StringUtils.isBlank(key)){
                return false;
            }
            return Boolean.TRUE.equals(redisTemplate.hasKey(key));
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }

    /**
     * 删除缓存
     *
     * @param key 可以传一个值 或多个
     */
    public static void remove(String... key) {
        if (key != null && key.length > 0) {
            try {
                for (String item : key) {
                    Set<String> keys = getRedisKeys(item);
                    if (keys==null||keys.size() == 0) {
                        redisTemplate.delete(item);
                    } else {
                        redisTemplate.delete(keys);
                    }

                }
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }
    }
    public static void remove(Collection<String> keys) {
        if (keys==null||keys.size() == 0) {
            redisTemplate.delete(keys);
        }
    }
    /**
     * 获取指定前缀的一系列key
     * 使用scan命令代替keys, Redis是单线程处理，keys命令在KEY数量较多时，
     * 操作效率极低【时间复杂度为O(N)】，该命令一旦执行会严重阻塞线上其它命令的正常请求
     *
     * @param realKey
     * @return
     */
    public static Set<String> getRedisKeys(String realKey) {
        try {
            return redisTemplate.keys(realKey + "*");
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return null;
    }

    /**
     * 删除指定前缀的一系列key
     *
     * @param keyPrefix
     */
    public static void removeAll(String keyPrefix) {
        try {
            Set<String> keys = getRedisKeys(keyPrefix);
            redisTemplate.delete(keys);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    public static void removeByPre(String keyPrefix) {
        try {
            Set<String> keys = redisTemplate.keys(keyPrefix + "*");
            redisTemplate.delete(keys);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
    // ============================String=============================

    /**
     * 普通缓存获取
     *
     * @param key 键
     * @return 值
     */
    public static Object get(String key) {
        if (key == null) {
            return null;
        }
        return redisTemplate.opsForValue().get(key);
    }


    public static <T> T get(String key, Class<T> clazz) {
        if (StringUtils.isBlank(key)) {
            return null;
        }
        String v = String.valueOf(get(key));
        if(v==null) return null;
        T t = JsonUtil.readObjectFromString(v, clazz);
        return t;
    }
    /**
     * 普通缓存放入
     *
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */
    public static boolean set(String key, Object value) {
        if (key == null || value == null) {
            return false;
        }
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }
    public static boolean set(String key, Object value,Integer expireTimeout) {
        if (key == null || value == null) {
            return false;
        }
        if(expireTimeout==null){
            expireTimeout=-1;
        }
        try {
            redisTemplate.opsForValue().set(key, value, expireTimeout, TimeUnit.SECONDS);
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }
    public static boolean set(String key, Object value,Integer expireTimeout,TimeUnit timeUnit) {
        if (key == null || value == null) {
            return false;
        }
        if(expireTimeout==null){
            expireTimeout=-1;
        }
        try {
            redisTemplate.opsForValue().set(key, value, expireTimeout, timeUnit);
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }
}
